package genetic;

public class Main {

	static int populationSize = 40;
	static int iterations = 1000;
	static int tournamentSize = 10;
	static double crossoverRate = 0.6;
	static double mutationRate = 0.2;
	static double contiguity = 0.5;

	public static Individual genetic(int populationSize,double crossoverRate,double mutationRate,Select select, int iterations, IndividualFactory individualFactory, Crossover crossover) {
		Population pop = Population.randomPopulation(individualFactory,populationSize);
		Individual best = individualFactory.randomIndividual();
		for (int i = 0; i < iterations; i++) {
			Population newpop = new Population();
			select.prepare(pop);
			while (newpop.size() < populationSize){
				Individual a = select.select(pop);
				Individual b = select.select(pop);
				if (Math.random() < crossoverRate)
					crossover.crossover(a,b);
				if (Math.random() < mutationRate)
					a.mutate();
				if (Math.random() < mutationRate)
					b.mutate();
				if (a.fitness() < best.fitness()) {
					best = a.clone();
				}
				if (b.fitness() < best.fitness()) {
					best = b.clone();	
				}
				newpop.add(a);
				newpop.add(b);
			}
			pop = newpop;
		}
		return best;
	}
	
	public static void testCrossover(IndividualFactory iF) {
		
		int rounds = 10;
		double totalLC = 0.0;
		double totalSBXC = 0.0;
		
		for(int i=0; i<rounds; i++){
			totalLC+=genetic(populationSize, 
						crossoverRate, 
						mutationRate,
						new TournamentSelect(tournamentSize), 
						iterations,
						iF,
						new LocalCrossover()).fitness();
			
			totalSBXC+=genetic(populationSize, 
						crossoverRate, 
						mutationRate,
						new TournamentSelect(tournamentSize), 
						iterations,
						iF,
						new SBXCrossover(contiguity)).fitness();
		}
		
		System.out.println("Local: " + totalLC/rounds + " -  SBX: " + totalSBXC/rounds);
	}
	
	public static void testSelection(IndividualFactory iF) {
		
		int rounds = 10;
		double totalTS = 0.0;
		double totalRS = 0.0;
		
		for(int i=0; i<rounds; i++){
			totalTS+=genetic(populationSize, 
						crossoverRate, 
						mutationRate,
						new TournamentSelect(tournamentSize), 
						iterations,
						iF,
						new SBXCrossover(contiguity)).fitness();
			
			totalRS+=genetic(populationSize, 
						crossoverRate, 
						mutationRate,
						new RouletteSelect(), 
						iterations,
						iF,
						new SBXCrossover(contiguity)).fitness();
		}
		
		System.out.println("Tournaments: " + totalTS/rounds + " - Roulette " + totalRS/rounds);
	}

	public static void mutationRateTest(){
		int numberOfPoints = 20;
		int rounds = 10;
		
		double[] xValue = new double[numberOfPoints+1];
		double[] yValue = new double[numberOfPoints+1];
		
				
		for(int x=0; x<=numberOfPoints; x++){
			double mR = x*(1.0/numberOfPoints);
			xValue[x]=mR;
	
			for(int i=0; i<rounds; i++){
				yValue[x]+= genetic(populationSize, 
						crossoverRate, 
						mR,
						new TournamentSelect(tournamentSize), 
						iterations,
						new F1IndividualFactory(),
						new LocalCrossover()).fitness();
			
			}
			yValue[x] = yValue[x]/rounds;
		}		
		GraphGenerator.printGraphic(xValue, yValue, "Pm X f1", "Mutation Rate", "Fitness", "MRF1");
	} 
	
	public static void popTest1000(){
		
		int numberOfPoints = 9;
		int iterations = 1000;
		int rounds = 10;
		
		double[] xValue = new double[numberOfPoints+1];
		double[] yValue = new double[numberOfPoints+1];
		
		for(int x=0; x<=numberOfPoints; x++){
			int pS = 10+x*10;
			xValue[x]=pS;
	
			for(int i=0; i<rounds; i++){
				yValue[x]+= genetic(pS, 
						crossoverRate, 
						mutationRate,
						new RouletteSelect(), 
						iterations,
						new F1IndividualFactory(),
						new SBXCrossover(contiguity)).fitness();
			
			}
			yValue[x] = yValue[x]/rounds;
		}		
		GraphGenerator.printGraphic(xValue, yValue, "Pop1000 X f1", "Population Size", "Fitness", "P1000F1");
	
	}
	
	public static void popTest50000(){
		
		int numberOfPoints = 9;
		int iterations = 50000;
		int rounds = 10;
		
		double[] xValue = new double[numberOfPoints+1];
		double[] yValue = new double[numberOfPoints+1];
		
		for(int x=0; x<=numberOfPoints; x++){
			int pS = 10+x*10;
			xValue[x]=pS;
	
			for(int i=0; i<rounds; i++){
				yValue[x]+= genetic(pS, 
						crossoverRate, 
						mutationRate,
						new RouletteSelect(), 
						iterations,
						new F1IndividualFactory(),
						new SBXCrossover(contiguity)).fitness();
			
			}
			yValue[x] = yValue[x]/rounds;
		}		
		GraphGenerator.printGraphic(xValue, yValue, "Pop50000 X f1", "Population Size", "Fitness", "P50000F1");
	
	}
	
	public static void crossoverRateTest(){
		int numberOfPoints = 20;
		int rounds = 10;
		
		double[] xValue = new double[numberOfPoints+1];
		double[] yValue = new double[numberOfPoints+1];
		
		for(int x=0; x<=numberOfPoints; x++){
			double cR = x*(1.0/numberOfPoints);
			xValue[x]=cR;
	
			for(int i=0; i<rounds; i++){
				yValue[x]+= genetic(populationSize, 
						cR, 
						mutationRate,
						new TournamentSelect(tournamentSize), 
						iterations,
						new F1IndividualFactory(),
						new SBXCrossover(contiguity)).fitness();
			
			}
			yValue[x] = yValue[x]/rounds;
		}		
		GraphGenerator.printGraphic(xValue, yValue, "Pc X f1", "Crossover Rate", "Fitness", "CRF1");
	
	}
	
	
	public static void main(String[] args) {

	//mutationRateTest();
	//crossoverRateTest();
	//popTest1000();
	//popTest50000();

	System.out.println("Crossover F1");
	Main.testCrossover(new F1IndividualFactory());
	System.out.println("Crossover F3");
	Main.testCrossover(new F3IndividualFactory());
	System.out.println("Selector F1");
	Main.testSelection(new F1IndividualFactory());
	System.out.println("Selector F3");
	Main.testSelection(new F3IndividualFactory());
	
	}
}
